Completed
Pull Request — master (#71)
by Marcelo
35s
created

input.js ➔ toInquirerQuestion   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
c 2
b 0
f 0
nc 3
nop 1
dl 0
loc 9
rs 9.6666
1
import { resolve } from 'bluebird';
2
import {
3
    T,
4
    __,
5
    assoc,
6
    concat,
7
    cond,
8
    curry,
9
    has,
10
    keys,
11
    map,
12
    merge,
13
    reduce,
14
    toPairs
15
} from 'ramda';
16
import { green, red, yellow } from 'colors/safe';
17
import { createPromptModule } from 'inquirer';
18
import { validator, filter } from './types';
19
import getAutocompleteSources, { compileClosure } from './autocomplete';
20
21
/**
22
 * Emits a warning to stdout
23
 *
24
 * @param {String} message
25
 * @return {Promise}
26
 */
27
export const emitWarning = concat(' ⚠ Warning: ') & yellow & console.log & resolve;
28
29
/**
30
 * Emits an error to stdout
31
 *
32
 * @param {String} message
33
 * @return {Promise}
34
 */
35
export const emitError = concat(' ✗ Error: ') & red & console.log & resolve;
36
37
/**
38
 * Emits a success message
39
 *
40
 * @param {String} message
41
 * @return {Promise}
42
 */
43
export const emitSuccess = concat(' ✔ Success: ') & green & console.log & resolve;
44
45
/**
46
 * Renames the keys of an object
47
 *
48
 * @sig {a: b} -> {a: *} -> {b: *}
49
 */
50
const renameKeys = curry((keysMap, obj) => reduce((acc, key) =>
51
    assoc(keysMap[key] || key, obj[key], acc), {}, keys(obj)));
52
53
const components = {
54
    Calendar: ~{
55
        type: 'datetime',
56
        format: ['m', '/', 'd', '/', 'yy'],
57
        filter: filter.Calendar },
58
    Char: ({ length }) => ({ filter: filter.Char(length) }),
59
    Checkbox: ~{ type: 'confirm' },
60
    Color: ~{ type: 'chalk-pipe' },
61
    DoubleRange: ({ from, to }) => ({
62
        filter: filter.Double,
63
        validate: validator.Range(from, to) }),
64
    DateTime: ~{ type: 'datetime' },
65
    Double: ~{ validate: validator.Double, filter: filter.Double },
66
    Email: ~{ validate: validator.Email },
67
    Integer: ~{ validate: validator.Integer, filter: filter.Integer },
68
    IntegerRange: ({ from, to }) => ({
69
        filter: filter.Integer,
70
        validate: validator.Range(from, to) }),
71
    IntegerMultiRange: ({ from, to }) => ({
72
        filter: filter.IntegerMultiRange,
73
        validate: validator.IntegerMultiRange(from, to) }),
74
    Natural: ~{ validate: validator.Natural, filter: filter.Integer },
75
    OneOf: ({ values }) => ({ type: 'list', choices: values }),
76
    String: ~{ type: 'input' },
77
    Url: ~{ validate: validator.Url },
78
    Money: ~{ validate: validator.Money, filter: filter.Money },
79
    SelectBox: ({ values }) => ({
80
        type: 'list',
81
        choices: values
82
            | toPairs
83
            | map(([value, name]) => ({ name, value })) })
84
};
85
86
/**
87
 * Custom autocomplete component
88
 *
89
 * @param {String} name
90
 * @param {String} source
91
 * @return {Function}
92
 */
93
const getAutocompleteComponent = (name, source) => {
94
    if (!source) {
95
        throw new Error(`aren't you missing 'autocomplete/${name}.js'?`);
96
    }
97
98
    return ~{ type: 'autocomplete', source: compileClosure(name, source) };
99
};
100
101
/**
102
 * Converts a Rung CLI question object to an Inquirer question object
103
 *
104
 * @author Marcelo Haskell Camargo
105
 * @param {String[]} sources
106
 * @param {String} name
0 ignored issues
show
Documentation introduced by
The parameter name does not exist. Did you maybe forget to remove this comment?
Loading history...
107
 * @param {Object} config
0 ignored issues
show
Documentation introduced by
The parameter config does not exist. Did you maybe forget to remove this comment?
Loading history...
108
 * @return {Object}
109
 */
110
const toInquirerQuestion = curry((sources, [name, config]) => {
111
    const component = components
112
        | cond([
113
            [~(config.type.name === 'AutoComplete'), ~getAutocompleteComponent(name, sources[name])],
114
            [has(config.type.name), _[config.type.name]],
0 ignored issues
show
Bug introduced by
The variable _ seems to be never declared. If this is a global, consider adding a /** global: _ */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
115
            [T, _.String]
116
        ]);
117
118
    return merge(config
119
        | renameKeys({ description: 'message' })
120
        | merge(__, { name }), component(config.type));
121
});
122
123
/**
124
 * Returns the pure JS values from received questions that will be answered
125
 *
126
 * @author Marcelo Haskell Camargo
127
 * @param {Object} questions
128
 * @return {Promise} answers for the questions by key
129
 */
130
export function ask(questions) {
131
    const DatePickerPrompt = require('inquirer-datepicker-prompt');
132
    const ChalkPipe = require('inquirer-chalk-pipe');
133
    const AutocompletePrompt = require('inquirer-autocomplete-prompt');
134
135
    const prompt = createPromptModule();
136
    prompt.registerPrompt('datetime', DatePickerPrompt);
137
    prompt.registerPrompt('chalk-pipe', ChalkPipe);
138
    prompt.registerPrompt('autocomplete', AutocompletePrompt);
139
    return getAutocompleteSources()
140
        .then(autocompleteSources => questions
141
            | toPairs
142
            | map(toInquirerQuestion(autocompleteSources))
143
            | prompt);
144
}
145